public class Test {
    private static int count = 0;

    public static void main(String[] args) throws Exception {
        var add = new Thread() {
            @Override
            public void run() {
                for (int i = 0; i < 10000; i++) {
                    count += 1;
                }
            }
        };
        var dec = new Thread() {
            @Override
            public void run() {
                for (int i = 0; i < 10000; i++) {
                    count = count - 1;
                }
            }
        };
        add.start();
        dec.start();
        add.join();
        dec.join();
        System.out.println(count); // 结果不一定是0，因为count += 1和count = count - 1不是原子操作
    }
}
// 局部变量只能读（必须 final/effectively final）；要改值，就用成员变量或原子类/锁
// 成员变量（类字段）存储在堆上，而局部变量存储在栈帧里。 栈帧随方法调用生/灭，
// 如果 Java 允许匿名内部类直接访问外层方法的非 final 局部变量，那么当方法返回、栈帧被销毁后，内部类对象手里就握着一个悬空指针 →
// 堆上的成员变量生命周期与对象一致，
// 内部类对象只要持有外部类的引用 (OuterClass.this)，就能安全、长久地读写那块内存，因此语法上无需 final 限制。

// effectively final 就是编译器自动推断的“隐形 final”：
// 如果一个局部变量在初始化后没有被重新赋值，那么它就是 effectively final 的，
// 即使没有显式地使用 final 关键字声明它，编译器也会将其视为 final 变量。
// 这种机制允许我们在不使用 final 关键字的情况下，将局部变量传递给匿名内部类或 Lambda 表达式，
// 只要我们确保该变量在初始化后不会被修改。
// 例如：
// int x = 10; // effectively final
// Runnable r = () -> System.out.println(x); // 这是合法的，因为 x 是 effectively final
// x = 20; // 如果取消注释这一行，x 就不再是 effectively final，编译器会报错